package river_city_ransom.contracts;

import exceptions.ComposantError;
import exceptions.InvariantError;
import exceptions.PostconditionError;
import exceptions.PreconditionError;
import river_city_ransom.services.Dimensions;
import river_city_ransom.services.Objet;
import river_city_ransom.services.Position;
import river_city_ransom.types.ObjetNom;
import tools.Toolbox;


public class Objet_C extends Equipable_C implements Objet {
	public Objet_C(Objet delegate) {
		super(delegate);
	}
	
	@Override
	protected Objet delegate() {
		return (Objet) super.delegate();
	}
	
	/** _________________________________________________________ OBSERVATORS */
	@Override
	public ObjetNom nom() {
		return delegate().nom();
	}
	
	@Override
	public int valeur() {
		return delegate().valeur();
	}
	
	@Override
	public int bonusDeForce() {
		return delegate().bonusDeForce();
	}
	
	@Override
	public boolean estMarchandable() {
		return delegate().estMarchandable();
	}
	
	/** __________________________________________________________ INVARIANTS */
	public void checkInvariants() throws ComposantError {
		super.checkInvariants();
		
		boolean inv;
//		inv (bonusDeForce(O) = 0 ^ valeur(O) > 0) v (bonusDeForce(O) > 0 ^ valeur(O) = 0)
		inv = (bonusDeForce() == 0 && valeur() > 0) || (bonusDeForce() > 0 && valeur() == 0);
		if(!inv) {
			throw new InvariantError("(bonusDeForce(O) = 0 ^ valeur(O) > 0) v (bonusDeForce(O) > 0 ^ valeur(O) = 0)");
		}
//		inv estEquipable(O) = bonusDeForce(O) > 0
		inv = estEquipable() == (bonusDeForce() > 0);
		if(!inv) {
			throw new InvariantError("estEquipable(O) = bonusDeForce(O) > 0");
		}
//		inv estMarchandable(O) = !estEquipable(O)
		inv = estMarchandable() == !estEquipable();
		if(!inv) {
			throw new InvariantError("estMarchandable(O) = !estEquipable(O)");
		}
	}
	
	/** ________________________________________________________ CONSTRUCTORS */
	@Override
	public void init(ObjetNom n) throws ComposantError {
		boolean pre;
//		pre init(n) require n != ""
		pre = n != null;
		if(!pre) {
			throw new PreconditionError("init(n) require n != \"\"");
		}
		
		delegate().init(n);
		
		checkInvariants();
		
		boolean post;
//		post nom(init(n)) = n
		post = nom() == n;
		if(!post) {
			throw new PreconditionError("nom(init(n)) = n");
		}
//		post estPorte(init(n, d, v, bf)) = false
		post = estPorte() == false;
		if(!post) {
			throw new PreconditionError("estPorte(init(n, d, v, bf)) = false");
		}
//		post estJete(init(n, d, v, bf)) = 0
		post = estJete() == 0;
		if(!post) {
			throw new PreconditionError("estJete(init(n, d, v, bf)) = 0");
		}
//		post position(init(n, d, v, bf)) = Position::init(0, 0, 0)
		Position p_init = position();
		p_init.init(0, 0, 0);
		post = Toolbox.equals(position(), p_init);
		if(!post) {
			throw new PostconditionError("position(init(n, d, v, bf)) = Position::init(0, 0, 0)");
		}
//		post si n = CINQUANTE_CENTIMES
		if(n == ObjetNom.CINQUANTE_CENTIME) {
//			post dimensions(init(n)) = Dimensions::init(5, 5, 1)
			Dimensions d_init = dimensions();
			d_init.init(5, 5, 1);
			post = Toolbox.equals(dimensions(), d_init);
			if(!post) {
				throw new PreconditionError("n = CINQUANTE_CENTIMES -> dimensions(init(n)) = Dimensions::init(5, 5, 1)");
			}
//			post valeur(init(n)) = 50
			post = valeur() == 50;
			if(!post) {
				throw new PreconditionError("n = CINQUANTE_CENTIMES -> valeur(init(n)) = 50");
			}
//			post bonusDeForce(init(n)) = 0
			post = bonusDeForce() == 0;
			if(!post) {
				throw new PreconditionError("n = CINQUANTE_CENTIMES -> bonusDeForce(init(n)) = 0");
			}
		}
//		post si n = UN_DOLLAR
		else if(n == ObjetNom.UN_DOLLAR) {
//			post dimensions(init(n)) = Dimensions::init(5, 5, 1)
			Dimensions d_init = dimensions();
			d_init.init(5, 5, 1);
			post = Toolbox.equals(dimensions(), d_init);
			if(!post) {
				throw new PreconditionError("n = UN_DOLLAR -> dimensions(init(n)) = Dimensions::init(5, 5, 1)");
			}
//			post valeur(init(n)) = 100
			post = valeur() == 100;
			if(!post) {
				throw new PreconditionError("n = UN_DOLLAR -> valeur(init(n)) = 100");
			}
//			post bonusDeForce(init(n)) = 0
			post = bonusDeForce() == 0;
			if(!post) {
				throw new PreconditionError("n = UN_DOLLAR -> bonusDeForce(init(n)) = 0");
			}
		}
//		post si n = CHAINE_DE_VELO
		else if(n == ObjetNom.CHAINE_DE_VELO) {
//			post dimensions(init(n)) = Dimensions::init(15, 5, 5)
			Dimensions d_init = dimensions();
			d_init.init(15, 5, 5);
			post = Toolbox.equals(dimensions(), d_init);
			if(!post) {
				throw new PreconditionError("n = CHAINE_DE_VELO -> dimensions(init(n)) = Dimensions::init(15, 5, 5)");
			}
//			post valeur(init(n)) = 0
			post = valeur() == 0;
			if(!post) {
				throw new PreconditionError("n = CHAINE_DE_VELO -> valeur(init(n)) = 0");
			}
//			post bonusDeForce(init(n)) = 10
			post = bonusDeForce() == 10;
			if(!post) {
				throw new PreconditionError("n = CHAINE_DE_VELO -> bonusDeForce(init(n)) = 10");
			}
		}
//		post si n = POUBELLE_METALLIQUE
		else if(n == ObjetNom.POUBELLE_METALLIQUE) {
//			post dimensions(init(n)) = Dimensions::init(15, 5, 5)
			Dimensions d_init = dimensions();
			d_init.init(10, 15, 10);
			post = Toolbox.equals(dimensions(), d_init);
			if(!post) {
				throw new PreconditionError("n = POUBELLE_METALLIQUE -> dimensions(init(n)) = Dimensions::init(10, 15, 10)");
			}
//			post valeur(init(n)) = 0
			post = valeur() == 0;
			if(!post) {
				throw new PreconditionError("n = POUBELLE_METALLIQUE -> valeur(init(n)) = 0");
			}
//			post bonusDeForce(init(n)) = 15
			post = bonusDeForce() == 15;
			if(!post) {
				throw new PreconditionError("n = POUBELLE_METALLIQUE -> bonusDeForce(init(n)) = 15");
			}
		}
	}
	
	/** ___________________________________________________________ OPERATORS */
	@Override
	public void deplacer(Position p) throws ComposantError {
		boolean ep_pre = estPorte();
		int ej_pre = estJete();
		
		checkInvariants();
		
		delegate().deplacer(p);
		
		checkInvariants();
		
		boolean post;
//		post estPorte(deplacer(O, p)) = estPorte(O)
		post = estPorte() == ep_pre;
		if(!post) {
			throw new PostconditionError("estPorte(deplacer(O, p)) = estPorte(O)");
		}
//		post estJete(deplacer(O, p)) = estJete(O)
		post = estJete() == ej_pre;
		if(!post) {
			throw new PostconditionError("estJete(deplacer(O, p)) = estJete(O)");
		}
//		post position(deplacer(P, p)) = p
		post = Toolbox.equals(position(), p);
		if(!post) {
			throw new PostconditionError("position(deplacer(P, p)) = p");
		}
	}
}
